package gosu;

import java.awt.event.*;
import static java.awt.event.KeyEvent.*;
import static java.awt.event.MouseEvent.*;
import java.util.*;

public enum Button {
  Kb1('1'),
  Kb2('2'),
  Kb3('3'),
  Kb4('4'),
  Kb5('5'),
  Kb6('6'),
  Kb7('7'),
  Kb8('8'),
  Kb9('9'),
  Kb0('0'),
  KbA('a'),
  KbB('b'),
  KbC('c'),
  KbD('d'),
  KbE('e'),
  KbF('f'),
  KbG('g'),
  KbH('h'),
  KbI('i'),
  KbJ('j'),
  KbK('k'),
  KbL('l'),
  KbM('m'),
  KbN('n'),
  KbO('o'),
  KbP('p'),
  KbQ('q'),
  KbR('r'),
  KbS('s'),
  KbT('t'),
  KbU('u'),
  KbV('v'),
  KbW('w'),
  KbX('x'),
  KbY('y'),
  KbZ('z'),
  KbBackspace,
  KbDelete,
  KbDown,
  KbEnd,
  KbEnter, // numpad
  KbEscape,
  KbF1,
  KbF2,
  KbF3,
  KbF4,
  KbF5,
  KbF6,
  KbF7,
  KbF8,
  KbF9,
  KbF10,
  KbF11,
  KbF12,
  KbHome,
  KbInsert,
  KbLeft,
  KbLeftAlt,
  KbLeftControl,
  KbLeftShift,
  KbNumpad0,
  KbNumpad1,
  KbNumpad2,
  KbNumpad3,
  KbNumpad4,
  KbNumpad5,
  KbNumpad6,
  KbNumpad7,
  KbNumpad8,
  KbNumpad9,
  KbNumpadAdd,
  KbNumpadDivide,
  KbNumpadMultiply,
  KbNumpadSubtract,
  KbPageDown,
  KbPageUp,
  KbPause,
  KbReturn, // center of keyboard
  KbRight,
  KbRightAlt,
  KbRightControl,
  KbRightShift,
  KbSpace(' '),
  KbTab,
  KbUp,
  KbSemicolon(';'),
  KbEquals('='),
  KbMinus('-'),
  KbOpenBracket('['),
  KbCloseBracket(']'),
  KbComma(','),
  KbPeriod('.'),
  KbSlash('/'),
  KbQuote('\''),
  KbBackSlash('\\'),
  KbBackQuote('`'),
  KbLeftMeta,
  KbRightMeta,

  MsLeft,
  MsRight,
  MsMiddle,
  MsWheelUp,
  MsWheelDown,

  GpLeft,
  GpRight,
  GpUp,
  GpDown,
  GpButton0,
  GpButton1,
  GpButton2,
  GpButton3,
  GpButton4,
  GpButton5,
  GpButton6,
  GpButton7,
  GpButton8,
  GpButton9,
  GpButton10,
  GpButton11,
  GpButton12,
  GpButton13,
  GpButton14,
  GpButton15,
        
  NoButton;

  private char _character;

  private Button() {
    _character = '\0';
  }

  private Button(char c) {
    _character = c;
  }

  public char toChar() { return _character; }


  private static final Map<Integer, Button> keyMap = new HashMap<Integer, Button>() {{
    put(VK_ESCAPE, KbEscape);
    put(VK_F1, KbF1);
    put(VK_F2, KbF2);
    put(VK_F3, KbF3);
    put(VK_F4, KbF4);
    put(VK_F5, KbF5);
    put(VK_F6, KbF6);
    put(VK_F7, KbF7);
    put(VK_F8, KbF8);
    put(VK_F9, KbF9);
    put(VK_F10, KbF10);
    put(VK_F11, KbF11);
    put(VK_F12, KbF12);
    put(VK_1, Kb1);
    put(VK_2, Kb2);
    put(VK_3, Kb3);
    put(VK_4, Kb4);
    put(VK_5, Kb5);
    put(VK_6, Kb6);
    put(VK_7, Kb7);
    put(VK_8, Kb8);
    put(VK_9, Kb9);
    put(VK_0, Kb0);
    put(VK_A, KbA);
    put(VK_B, KbB);
    put(VK_C, KbC);
    put(VK_D, KbD);
    put(VK_E, KbE);
    put(VK_F, KbF);
    put(VK_G, KbG);
    put(VK_H, KbH);
    put(VK_I, KbI);
    put(VK_J, KbJ);
    put(VK_K, KbK);
    put(VK_L, KbL);
    put(VK_M, KbM);
    put(VK_N, KbN);
    put(VK_O, KbO);
    put(VK_P, KbP);
    put(VK_Q, KbQ);
    put(VK_R, KbR);
    put(VK_S, KbS);
    put(VK_T, KbT);
    put(VK_U, KbU);
    put(VK_V, KbV);
    put(VK_W, KbW);
    put(VK_X, KbX);
    put(VK_Y, KbY);
    put(VK_Z, KbZ);
    put(VK_OPEN_BRACKET, KbOpenBracket);
    put(VK_CLOSE_BRACKET, KbCloseBracket);
    put(VK_BACK_SLASH, KbBackSlash);
    put(VK_SEMICOLON, KbSemicolon);
    put(VK_QUOTE, KbQuote);
    put(VK_COMMA, KbComma);
    put(VK_PERIOD, KbPeriod);
    put(VK_SLASH, KbSlash);
    put(VK_EQUALS, KbEquals);
    put(VK_MINUS, KbMinus);
    put(VK_BACK_QUOTE, KbBackQuote);
    put(VK_TAB, KbTab);
    put(VK_SPACE, KbSpace);
    put(VK_BACK_SPACE, KbBackspace);
    put(VK_LEFT, KbLeft);
    put(VK_RIGHT, KbRight);
    put(VK_UP, KbUp);
    put(VK_DOWN, KbDown);
    put(VK_HOME, KbHome);
    put(VK_END, KbEnd);
    put(VK_INSERT, KbInsert);
    put(VK_DELETE, KbDelete);
    put(VK_PAGE_UP, KbPageUp);
    put(VK_PAGE_DOWN, KbPageDown);
    put(VK_NUMPAD1, KbNumpad1);
    put(VK_NUMPAD2, KbNumpad2);
    put(VK_NUMPAD3, KbNumpad3);
    put(VK_NUMPAD4, KbNumpad4);
    put(VK_NUMPAD5, KbNumpad5);
    put(VK_NUMPAD6, KbNumpad6);
    put(VK_NUMPAD7, KbNumpad7);
    put(VK_NUMPAD8, KbNumpad8);
    put(VK_NUMPAD9, KbNumpad9);
    put(VK_NUMPAD0, KbNumpad0);
  }};


  private static final Map<Character, Button> charMap = new HashMap<Character, Button>() {{
    put('1', Kb1);
    put('2', Kb2);
    put('3', Kb3);
    put('4', Kb4);
    put('5', Kb5);
    put('6', Kb6);
    put('7', Kb7);
    put('8', Kb8);
    put('9', Kb9);
    put('0', Kb0);
    put('a', KbA);
    put('b', KbB);
    put('c', KbC);
    put('d', KbD);
    put('e', KbE);
    put('f', KbF);
    put('g', KbG);
    put('h', KbH);
    put('i', KbI);
    put('j', KbJ);
    put('k', KbK);
    put('l', KbL);
    put('m', KbM);
    put('n', KbN);
    put('o', KbO);
    put('p', KbP);
    put('q', KbQ);
    put('r', KbR);
    put('s', KbS);
    put('t', KbT);
    put('u', KbU);
    put('v', KbV);
    put('w', KbW);
    put('x', KbX);
    put('y', KbY);
    put('z', KbZ);
    put('-', KbMinus);
    put('=', KbEquals);
    put('[', KbOpenBracket);
    put(']', KbCloseBracket);
    put('\\', KbBackSlash);
    put(';', KbSemicolon);
    put('\'', KbQuote);
    put(',', KbComma);
    put('.', KbPeriod);
    put('/', KbSlash);
    put(' ', KbSpace);
  }};


  public static Button getButton(char c) {
    Button button = charMap.get(c);
    return (button != null) ? button : NoButton;
  }


  public static Button getButton(InputEvent e) {
    if (e instanceof KeyEvent) {
      return getButton((KeyEvent) e);
    } else if (e instanceof MouseEvent) {
      return getButton((MouseEvent) e);
    }

    return NoButton;
  }

  public static Button getButton(MouseEvent e) {
    switch (e.getButton()) {
      case BUTTON1:
        return MsLeft;
      case BUTTON2:
        return MsMiddle;
      case BUTTON3:
        return MsRight;
    }

    if (e.getID() == MOUSE_WHEEL) {
      //FIXME: There may be more than one 'click', so we need to deal with those somehow
      MouseWheelEvent mwEvent = (MouseWheelEvent) e;
      if (mwEvent.getWheelRotation() > 0) {
        return MsWheelDown;
      } else {
        return MsWheelUp;
      }
    }

    return NoButton;
  }

  public static Button getButton(KeyEvent e) {
    Button button = keyMap.get(e.getKeyCode());
    if (button != null) return button;

    // The button pressed exists more than once on the keyboard.
    // Find out specifically which button was pressed.
    switch (e.getKeyCode()) {
      case VK_SHIFT:
        if (e.getKeyLocation() == KEY_LOCATION_LEFT) {
          return KbLeftShift;
        } else {
          return KbRightShift;
        }
      case VK_ALT:
        if (e.getKeyLocation() == KEY_LOCATION_LEFT) {
          return KbLeftAlt;
        } else {
          return KbRightAlt;
        }
      case VK_CONTROL:
        if (e.getKeyLocation() == KEY_LOCATION_LEFT) {
          return KbLeftControl;
        } else {
          return KbRightControl;
        }
      case VK_META:
        if (e.getKeyLocation() == KEY_LOCATION_LEFT) {
          return KbLeftMeta;
        } else {
          return KbRightMeta;
        }
      case VK_ENTER:
        if (e.getKeyLocation() == KEY_LOCATION_NUMPAD) {
          return KbEnter;
        } else {
          return KbReturn;
        }
      default:
        return NoButton;
    }
  }
}
